home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / HTML / QuickForm.php < prev    next >
PHP Script  |  2004-10-01  |  68KB  |  1,826 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Adam Daniel <adaniel1@eesus.jnj.com>                        |
  17. // |          Bertrand Mansion <bmansion@mamasam.com>                     |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: QuickForm.php,v 1.144 2004/06/15 10:51:42 mansion Exp $
  21.  
  22. require_once('PEAR.php');
  23. require_once('HTML/Common.php');
  24.  
  25. $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'] = 
  26.         array(
  27.             'group'         =>array('HTML/QuickForm/group.php','HTML_QuickForm_group'),
  28.             'hidden'        =>array('HTML/QuickForm/hidden.php','HTML_QuickForm_hidden'),
  29.             'reset'         =>array('HTML/QuickForm/reset.php','HTML_QuickForm_reset'),
  30.             'checkbox'      =>array('HTML/QuickForm/checkbox.php','HTML_QuickForm_checkbox'),
  31.             'file'          =>array('HTML/QuickForm/file.php','HTML_QuickForm_file'),
  32.             'image'         =>array('HTML/QuickForm/image.php','HTML_QuickForm_image'),
  33.             'password'      =>array('HTML/QuickForm/password.php','HTML_QuickForm_password'),
  34.             'radio'         =>array('HTML/QuickForm/radio.php','HTML_QuickForm_radio'),
  35.             'button'        =>array('HTML/QuickForm/button.php','HTML_QuickForm_button'),
  36.             'submit'        =>array('HTML/QuickForm/submit.php','HTML_QuickForm_submit'),
  37.             'select'        =>array('HTML/QuickForm/select.php','HTML_QuickForm_select'),
  38.             'hiddenselect'  =>array('HTML/QuickForm/hiddenselect.php','HTML_QuickForm_hiddenselect'),
  39.             'text'          =>array('HTML/QuickForm/text.php','HTML_QuickForm_text'),
  40.             'textarea'      =>array('HTML/QuickForm/textarea.php','HTML_QuickForm_textarea'),
  41.             'link'          =>array('HTML/QuickForm/link.php','HTML_QuickForm_link'),
  42.             'advcheckbox'   =>array('HTML/QuickForm/advcheckbox.php','HTML_QuickForm_advcheckbox'),
  43.             'date'          =>array('HTML/QuickForm/date.php','HTML_QuickForm_date'),
  44.             'static'        =>array('HTML/QuickForm/static.php','HTML_QuickForm_static'),
  45.             'header'        =>array('HTML/QuickForm/header.php', 'HTML_QuickForm_header'),
  46.             'html'          =>array('HTML/QuickForm/html.php', 'HTML_QuickForm_html'),
  47.             'hierselect'    =>array('HTML/QuickForm/hierselect.php', 'HTML_QuickForm_hierselect'),
  48.             'autocomplete'  =>array('HTML/QuickForm/autocomplete.php', 'HTML_QuickForm_autocomplete'),
  49.             'xbutton'       =>array('HTML/QuickForm/xbutton.php','HTML_QuickForm_xbutton')
  50.         );
  51.  
  52. $GLOBALS['_HTML_QuickForm_registered_rules'] = array(
  53.     'required'      => array('html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'),
  54.     'maxlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  55.     'minlength'     => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  56.     'rangelength'   => array('html_quickform_rule_range',    'HTML/QuickForm/Rule/Range.php'),
  57.     'email'         => array('html_quickform_rule_email',    'HTML/QuickForm/Rule/Email.php'),
  58.     'regex'         => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  59.     'lettersonly'   => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  60.     'alphanumeric'  => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  61.     'numeric'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  62.     'nopunctuation' => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  63.     'nonzero'       => array('html_quickform_rule_regex',    'HTML/QuickForm/Rule/Regex.php'),
  64.     'callback'      => array('html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'),
  65.     'compare'       => array('html_quickform_rule_compare',  'HTML/QuickForm/Rule/Compare.php')
  66. );
  67.  
  68. // {{{ error codes
  69.  
  70. /*
  71.  * Error codes for the QuickForm interface, which will be mapped to textual messages
  72.  * in the QuickForm::errorMessage() function.  If you are to add a new error code, be
  73.  * sure to add the textual messages to the QuickForm::errorMessage() function as well
  74.  */
  75.  
  76. define('QUICKFORM_OK',                      1);
  77. define('QUICKFORM_ERROR',                  -1);
  78. define('QUICKFORM_INVALID_RULE',           -2);
  79. define('QUICKFORM_NONEXIST_ELEMENT',       -3);
  80. define('QUICKFORM_INVALID_FILTER',         -4);
  81. define('QUICKFORM_UNREGISTERED_ELEMENT',   -5);
  82. define('QUICKFORM_INVALID_ELEMENT_NAME',   -6);
  83. define('QUICKFORM_INVALID_PROCESS',        -7);
  84. define('QUICKFORM_DEPRECATED',             -8);
  85. define('QUICKFORM_INVALID_DATASOURCE',     -9);
  86.  
  87. // }}}
  88.  
  89. /**
  90. * Create, validate and process HTML forms
  91. *
  92. * @author      Adam Daniel <adaniel1@eesus.jnj.com>
  93. * @author      Bertrand Mansion <bmansion@mamasam.com>
  94. * @version     2.0
  95. * @since       PHP 4.0.3pl1
  96. */
  97. class HTML_QuickForm extends HTML_Common {
  98.     // {{{ properties
  99.  
  100.     /**
  101.      * Array containing the form fields
  102.      * @since     1.0
  103.      * @var  array
  104.      * @access   private
  105.      */
  106.     var $_elements = array();
  107.  
  108.     /**
  109.      * Array containing element name to index map
  110.      * @since     1.1
  111.      * @var  array
  112.      * @access   private
  113.      */
  114.     var $_elementIndex = array();
  115.  
  116.     /**
  117.      * Array containing indexes of duplicate elements
  118.      * @since     2.10
  119.      * @var  array
  120.      * @access   private
  121.      */
  122.     var $_duplicateIndex = array();
  123.  
  124.     /**
  125.      * Array containing required field IDs
  126.      * @since     1.0
  127.      * @var  array
  128.      * @access   private
  129.      */ 
  130.     var $_required = array();
  131.  
  132.     /**
  133.      * Prefix message in javascript alert if error
  134.      * @since     1.0
  135.      * @var  string
  136.      * @access   public
  137.      */ 
  138.     var $_jsPrefix = 'Invalid information entered.';
  139.  
  140.     /**
  141.      * Postfix message in javascript alert if error
  142.      * @since     1.0
  143.      * @var  string
  144.      * @access   public
  145.      */ 
  146.     var $_jsPostfix = 'Please correct these fields.';
  147.  
  148.     /**
  149.      * Datasource object implementing the informal
  150.      * datasource protocol
  151.      * @since     3.3
  152.      * @var  object
  153.      * @access   private
  154.      */
  155.     var $_datasource;
  156.  
  157.     /**
  158.      * Array of default form values
  159.      * @since     2.0
  160.      * @var  array
  161.      * @access   private
  162.      */
  163.     var $_defaultValues = array();
  164.  
  165.     /**
  166.      * Array of constant form values
  167.      * @since     2.0
  168.      * @var  array
  169.      * @access   private
  170.      */
  171.     var $_constantValues = array();
  172.  
  173.     /**
  174.      * Array of submitted form values
  175.      * @since     1.0
  176.      * @var  array
  177.      * @access   private
  178.      */
  179.     var $_submitValues = array();
  180.  
  181.     /**
  182.      * Array of submitted form files
  183.      * @since     1.0
  184.      * @var  integer
  185.      * @access   public
  186.      */
  187.     var $_submitFiles = array();
  188.  
  189.     /**
  190.      * Value for maxfilesize hidden element if form contains file input
  191.      * @since     1.0
  192.      * @var  integer
  193.      * @access   public
  194.      */
  195.     var $_maxFileSize = 1048576; // 1 Mb = 1048576
  196.  
  197.     /**
  198.      * Flag to know if all fields are frozen
  199.      * @since     1.0
  200.      * @var  boolean
  201.      * @access   private
  202.      */
  203.     var $_freezeAll = false;
  204.  
  205.     /**
  206.      * Array containing the form rules
  207.      * @since     1.0
  208.      * @var  array
  209.      * @access   private
  210.      */
  211.     var $_rules = array();
  212.  
  213.     /**
  214.      * Form rules, global variety
  215.      * @var     array
  216.      * @access  private
  217.      */
  218.     var $_formRules = array();
  219.  
  220.     /**
  221.      * Array containing the validation errors
  222.      * @since     1.0
  223.      * @var  array
  224.      * @access   private
  225.      */
  226.     var $_errors = array();
  227.  
  228.     /**
  229.      * Note for required fields in the form
  230.      * @var       string
  231.      * @since     1.0
  232.      * @access    public
  233.      */
  234.     var $_requiredNote = '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>';
  235.  
  236.     // }}}
  237.     // {{{ constructor
  238.  
  239.     /**
  240.      * Class constructor
  241.      * @param    string      $formName          Form's name.
  242.      * @param    string      $method            (optional)Form's method defaults to 'POST'
  243.      * @param    string      $action            (optional)Form's action
  244.      * @param    string      $target            (optional)Form's target defaults to '_self'
  245.      * @param    mixed       $attributes        (optional)Extra attributes for <form> tag
  246.      * @param    bool        $trackSubmit       (optional)Whether to track if the form was submitted by adding a special hidden field
  247.      * @access   public
  248.      */
  249.     function HTML_QuickForm($formName='', $method='post', $action='', $target='_self', $attributes=null, $trackSubmit = false)
  250.     {
  251.         HTML_Common::HTML_Common($attributes);
  252.         $method = (strtoupper($method) == 'GET') ? 'get' : 'post';
  253.         $action = ($action == '') ? $_SERVER['PHP_SELF'] : $action;
  254.         $target = (empty($target) || $target == '_self') ? array() : array('target' => $target);
  255.         $attributes = array('action'=>$action, 'method'=>$method, 'name'=>$formName, 'id'=>$formName) + $target;
  256.         $this->updateAttributes($attributes);
  257.         if (!$trackSubmit || isset($_REQUEST['_qf__' . $formName])) {
  258.             if (1 == get_magic_quotes_gpc()) {
  259.                 $this->_submitValues = $this->_recursiveFilter('stripslashes', 'get' == $method? $_GET: $_POST);
  260.                 $this->_submitFiles  = $this->_recursiveFilter('stripslashes', $_FILES);
  261.             } else {
  262.                 $this->_submitValues = 'get' == $method? $_GET: $_POST;
  263.                 $this->_submitFiles  = $_FILES;
  264.             }
  265.         }
  266.         if ($trackSubmit) {
  267.             unset($this->_submitValues['_qf__' . $formName]);
  268.             $this->addElement('hidden', '_qf__' . $formName, null);
  269.         }
  270.     } // end constructor
  271.  
  272.     // }}}
  273.     // {{{ apiVersion()
  274.  
  275.     /**
  276.      * Returns the current API version
  277.      *
  278.      * @since     1.0
  279.      * @access    public
  280.      * @return    float
  281.      */
  282.     function apiVersion()
  283.     {
  284.         return 3.2;
  285.     } // end func apiVersion
  286.  
  287.     // }}}
  288.     // {{{ registerElementType()
  289.  
  290.     /**
  291.      * Registers a new element type
  292.      *
  293.      * @param     string    $typeName   Name of element type
  294.      * @param     string    $include    Include path for element type
  295.      * @param     string    $className  Element class name
  296.      * @since     1.0
  297.      * @access    public
  298.      * @return    void
  299.      */
  300.     function registerElementType($typeName, $include, $className)
  301.     {
  302.         $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][strtolower($typeName)] = array($include, $className);
  303.     } // end func registerElementType
  304.  
  305.     // }}}
  306.     // {{{ registerRule()
  307.  
  308.     /**
  309.      * Registers a new validation rule
  310.      *
  311.      * @param     string    $ruleName   Name of validation rule
  312.      * @param     string    $type       Either: 'regex', 'function' or 'rule' for an HTML_QuickForm_Rule object
  313.      * @param     string    $data1      Name of function, regular expression or HTML_QuickForm_Rule classname
  314.      * @param     string    $data2      Object parent of above function or HTML_QuickForm_Rule file path
  315.      * @since     1.0
  316.      * @access    public
  317.      * @return    void
  318.      */
  319.     function registerRule($ruleName, $type, $data1, $data2 = null)
  320.     {
  321.         include_once('HTML/QuickForm/RuleRegistry.php');
  322.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  323.         $registry->registerRule($ruleName, $type, $data1, $data2);
  324.     } // end func registerRule
  325.  
  326.     // }}}
  327.     // {{{ elementExists()
  328.  
  329.     /**
  330.      * Returns true if element is in the form
  331.      *
  332.      * @param     string   $element         form name of element to check
  333.      * @since     1.0
  334.      * @access    public
  335.      * @return    boolean
  336.      */
  337.     function elementExists($element=null)
  338.     {
  339.         return isset($this->_elementIndex[$element]);
  340.     } // end func elementExists
  341.  
  342.     // }}}
  343.     // {{{ setDatasource()
  344.  
  345.     /**
  346.      * Sets a datasource object for this form object
  347.      *
  348.      * Datasource default and constant values will feed the QuickForm object if
  349.      * the datasource implements defaultValues() and constantValues() methods.
  350.      *
  351.      * @param     object   $datasource          datasource object implementing the informal datasource protocol
  352.      * @param     mixed    $defaultsFilter      string or array of filter(s) to apply to default values
  353.      * @param     mixed    $constantsFilter     string or array of filter(s) to apply to constants values
  354.      * @since     3.3
  355.      * @access    public
  356.      * @return    void
  357.      */
  358.     function setDatasource(&$datasource, $defaultsFilter = null, $constantsFilter = null)
  359.     {
  360.         if (is_object($datasource)) {
  361.             $this->_datasource =& $datasource;
  362.             if (is_callable(array($datasource, 'defaultValues'))) {
  363.                 $this->setDefaults($datasource->defaultValues($this), $defaultsFilter);
  364.             }
  365.             if (is_callable(array($datasource, 'constantValues'))) {
  366.                 $this->setConstants($datasource->constantValues($this), $constantsFilter);
  367.             }
  368.         } else {
  369.             return PEAR::raiseError(null, QUICKFORM_INVALID_DATASOURCE, null, E_USER_WARNING, "Datasource is not an object in QuickForm::setDatasource()", 'HTML_QuickForm_Error', true);
  370.         }
  371.     } // end func setDatasource
  372.  
  373.     // }}}
  374.     // {{{ setDefaults()
  375.  
  376.     /**
  377.      * Initializes default form values
  378.      *
  379.      * @param     array    $defaultValues       values used to fill the form
  380.      * @param     mixed    $filter              (optional) filter(s) to apply to all default values
  381.      * @since     1.0
  382.      * @access    public
  383.      * @return    void
  384.      */
  385.     function setDefaults($defaultValues = null, $filter = null)
  386.     {
  387.         if (is_array($defaultValues)) {
  388.             if (isset($filter)) {
  389.                 if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  390.                     foreach ($filter as $val) {
  391.                         if (!is_callable($val)) {
  392.                             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  393.                         } else {
  394.                             $defaultValues = $this->_recursiveFilter($val, $defaultValues);
  395.                         }
  396.                     }
  397.                 } elseif (!is_callable($filter)) {
  398.                     return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setDefaults()", 'HTML_QuickForm_Error', true);
  399.                 } else {
  400.                     $defaultValues = $this->_recursiveFilter($filter, $defaultValues);
  401.                 }
  402.             }
  403.             $this->_defaultValues = HTML_QuickForm::arrayMerge($this->_defaultValues, $defaultValues);
  404.             foreach (array_keys($this->_elements) as $key) {
  405.                 $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  406.             }
  407.         }
  408.     } // end func setDefaults
  409.  
  410.     // }}}
  411.     // {{{ setConstants()
  412.  
  413.     /**
  414.      * Initializes constant form values.
  415.      * These values won't get overridden by POST or GET vars
  416.      *
  417.      * @param     array   $constantValues        values used to fill the form    
  418.      * @param     mixed    $filter              (optional) filter(s) to apply to all default values    
  419.      *
  420.      * @since     2.0
  421.      * @access    public
  422.      * @return    void
  423.      */
  424.     function setConstants($constantValues = null, $filter = null)
  425.     {
  426.         if (is_array($constantValues)) {
  427.             if (isset($filter)) {
  428.                 if (is_array($filter) && (2 != count($filter) || !is_callable($filter))) {
  429.                     foreach ($filter as $val) {
  430.                         if (!is_callable($val)) {
  431.                             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  432.                         } else {
  433.                             $constantValues = $this->_recursiveFilter($val, $constantValues);
  434.                         }
  435.                     }
  436.                 } elseif (!is_callable($filter)) {
  437.                     return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::setConstants()", 'HTML_QuickForm_Error', true);
  438.                 } else {
  439.                     $constantValues = $this->_recursiveFilter($filter, $constantValues);
  440.                 }
  441.             }
  442.             $this->_constantValues = HTML_QuickForm::arrayMerge($this->_constantValues, $constantValues);
  443.             foreach (array_keys($this->_elements) as $key) {
  444.                 $this->_elements[$key]->onQuickFormEvent('updateValue', null, $this);
  445.             }
  446.         }
  447.     } // end func setConstants
  448.  
  449.     // }}}
  450.     // {{{ setMaxFileSize()
  451.  
  452.     /**
  453.      * Sets the value of MAX_FILE_SIZE hidden element
  454.      *
  455.      * @param     int    $bytes    Size in bytes
  456.      * @since     3.0
  457.      * @access    public
  458.      * @return    void
  459.      */
  460.     function setMaxFileSize($bytes = 0)
  461.     {
  462.         if ($bytes > 0) {
  463.             $this->_maxFileSize = $bytes;
  464.         }
  465.         if (!$this->elementExists('MAX_FILE_SIZE')) {
  466.             $this->addElement('hidden', 'MAX_FILE_SIZE', $this->_maxFileSize);
  467.         } else {
  468.             $el =& $this->getElement('MAX_FILE_SIZE');
  469.             $el->updateAttributes(array('value' => $this->_maxFileSize));
  470.         }
  471.     } // end func setMaxFileSize
  472.  
  473.     // }}}
  474.     // {{{ getMaxFileSize()
  475.  
  476.     /**
  477.      * Returns the value of MAX_FILE_SIZE hidden element
  478.      *
  479.      * @since     3.0
  480.      * @access    public
  481.      * @return    int   max file size in bytes
  482.      */
  483.     function getMaxFileSize()
  484.     {
  485.         return $this->_maxFileSize;
  486.     } // end func getMaxFileSize
  487.  
  488.     // }}}
  489.     // {{{ &createElement()
  490.  
  491.     /**
  492.      * Creates a new form element of the given type.
  493.      * 
  494.      * This method accepts variable number of parameters, their 
  495.      * meaning and count depending on $elementType
  496.      *
  497.      * @param     string     $elementType    type of element to add (text, textarea, file...)
  498.      * @since     1.0
  499.      * @access    public
  500.      * @return    object extended class of HTML_element
  501.      * @throws    HTML_QuickForm_Error
  502.      */
  503.     function &createElement($elementType)
  504.     {
  505.         $args = func_get_args();
  506.         return HTML_QuickForm::_loadElement('createElement', $elementType, array_slice($args, 1));
  507.     } // end func createElement
  508.     
  509.     // }}}
  510.     // {{{ _loadElement()
  511.  
  512.     /**
  513.      * Returns a form element of the given type
  514.      *
  515.      * @param     string   $event   event to send to newly created element ('createElement' or 'addElement')
  516.      * @param     string   $type    element type
  517.      * @param     array    $args    arguments for event
  518.      * @since     2.0
  519.      * @access    private
  520.      * @return    object    a new element
  521.      * @throws    HTML_QuickForm_Error
  522.      */
  523.     function &_loadElement($event, $type, $args)
  524.     {
  525.         $type = strtolower($type);
  526.         if (!HTML_QuickForm::isTypeRegistered($type)) {
  527.             return PEAR::raiseError(null, QUICKFORM_UNREGISTERED_ELEMENT, null, E_USER_WARNING, "Element '$type' does not exist in HTML_QuickForm::_loadElement()", 'HTML_QuickForm_Error', true);
  528.         }
  529.         $className = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][1];
  530.         $includeFile = $GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type][0];
  531.         include_once($includeFile);
  532.         $elementObject =& new $className();
  533.         for ($i = 0; $i < 5; $i++) {
  534.             if (!isset($args[$i])) {
  535.                 $args[$i] = null;
  536.             }
  537.         }
  538.         $err = $elementObject->onQuickFormEvent($event, $args, $this);
  539.         if ($err !== true) {
  540.             return $err;
  541.         }
  542.         return $elementObject;
  543.     } // end func _loadElement
  544.  
  545.     // }}}
  546.     // {{{ addElement()
  547.  
  548.     /**
  549.      * Adds an element into the form
  550.      * 
  551.      * If $element is a string representing element type, then this 
  552.      * method accepts variable number of parameters, their meaning 
  553.      * and count depending on $element
  554.      *
  555.      * @param    mixed      $element        element object or type of element to add (text, textarea, file...)
  556.      * @since    1.0
  557.      * @return   object     reference to element
  558.      * @access   public
  559.      * @throws   HTML_QuickForm_Error
  560.      */
  561.     function &addElement($element)
  562.     {
  563.         if (is_object($element) && is_subclass_of($element, 'html_quickform_element')) {
  564.            $elementObject = &$element;
  565.            $elementObject->onQuickFormEvent('updateValue', null, $this);
  566.         } else {
  567.             $args = func_get_args();
  568.             $elementObject =& $this->_loadElement('addElement', $element, array_slice($args, 1));
  569.             if (PEAR::isError($elementObject)) {
  570.                 return $elementObject;
  571.             }
  572.         }
  573.         $elementName = $elementObject->getName();
  574.  
  575.         // Add the element if it is not an incompatible duplicate
  576.         if (!empty($elementName) && isset($this->_elementIndex[$elementName])) {
  577.             if ($this->_elements[$this->_elementIndex[$elementName]]->getType() ==
  578.                 $elementObject->getType()) {
  579.                 $this->_elements[] =& $elementObject;
  580.                 $this->_duplicateIndex[$elementName][] = end(array_keys($this->_elements));
  581.             } else {
  582.                 return PEAR::raiseError(null, QUICKFORM_INVALID_ELEMENT_NAME, null, E_USER_WARNING, "Element '$elementName' already exists in HTML_QuickForm::addElement()", 'HTML_QuickForm_Error', true);
  583.             }
  584.         } else {
  585.             $this->_elements[] =& $elementObject;
  586.             $this->_elementIndex[$elementName] = end(array_keys($this->_elements));
  587.         }
  588.  
  589.         return $elementObject;
  590.     } // end func addElement
  591.     
  592.     // }}}
  593.     // {{{ addGroup()
  594.  
  595.     /**
  596.      * Adds an element group
  597.      * @param    array      $elements       array of elements composing the group
  598.      * @param    string     $name           (optional)group name
  599.      * @param    string     $groupLabel     (optional)group label
  600.      * @param    string     $separator      (optional)string to separate elements
  601.      * @param    string     $appendName     (optional)specify whether the group name should be
  602.      *                                      used in the form element name ex: group[element]
  603.      * @return   object     reference to added group of elements
  604.      * @since    2.8
  605.      * @access   public
  606.      * @throws   PEAR_Error
  607.      */
  608.     function &addGroup($elements, $name=null, $groupLabel='', $separator=null, $appendName = true)
  609.     {
  610.         static $anonGroups = 1;
  611.  
  612.         if (0 == strlen($name)) {
  613.             $name       = 'qf_group_' . $anonGroups++;
  614.             $appendName = false;
  615.         }
  616.         return $this->addElement('group', $name, $groupLabel, $elements, $separator, $appendName);
  617.     } // end func addGroup
  618.     
  619.     // }}}
  620.     // {{{ &getElement()
  621.  
  622.     /**
  623.      * Returns a reference to the element
  624.      *
  625.      * @param     string     $element    Element name
  626.      * @since     2.0
  627.      * @access    public
  628.      * @return    object     reference to element
  629.      * @throws    HTML_QuickForm_Error
  630.      */
  631.     function &getElement($element)
  632.     {
  633.         if (isset($this->_elementIndex[$element])) {
  634.             return $this->_elements[$this->_elementIndex[$element]];
  635.         } else {
  636.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElement()", 'HTML_QuickForm_Error', true);
  637.         }
  638.     } // end func getElement
  639.  
  640.     // }}}
  641.     // {{{ &getElementValue()
  642.  
  643.     /**
  644.      * Returns the element's raw value
  645.      * 
  646.      * This returns the value as submitted by the form (not filtered) 
  647.      * or set via setDefaults() or setConstants()
  648.      *
  649.      * @param     string     $element    Element name
  650.      * @since     2.0
  651.      * @access    public
  652.      * @return    mixed     element value
  653.      * @throws    HTML_QuickForm_Error
  654.      */
  655.     function &getElementValue($element)
  656.     {
  657.         if (!isset($this->_elementIndex[$element])) {
  658.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  659.         }
  660.         $value = $this->_elements[$this->_elementIndex[$element]]->getValue();
  661.         if (isset($this->_duplicateIndex[$element])) {
  662.             foreach ($this->_duplicateIndex[$element] as $index) {
  663.                 if (null !== ($v = $this->_elements[$index]->getValue())) {
  664.                     if (is_array($value)) {
  665.                         $value[] = $v;
  666.                     } else {
  667.                         $value = (null === $value)? $v: array($value, $v);
  668.                     }
  669.                 }
  670.             }
  671.         }
  672.         return $value;
  673.     } // end func getElementValue
  674.  
  675.     // }}}
  676.     // {{{ getSubmitValue()
  677.  
  678.     /**
  679.      * Returns the elements value after submit and filter
  680.      *
  681.      * @param     string     Element name
  682.      * @since     2.0
  683.      * @access    public
  684.      * @return    mixed     submitted element value or null if not set
  685.      */    
  686.     function getSubmitValue($elementName)
  687.     {
  688.         $value = null;
  689.         if (isset($this->_submitValues[$elementName]) || isset($this->_submitFiles[$elementName])) {
  690.             $value = isset($this->_submitValues[$elementName])? $this->_submitValues[$elementName]: array();
  691.             if (is_array($value) && isset($this->_submitFiles[$elementName])) {
  692.                 foreach ($this->_submitFiles[$elementName] as $k => $v) {
  693.                     $value = HTML_QuickForm::arrayMerge($value, $this->_reindexFiles($this->_submitFiles[$elementName][$k], $k));
  694.                 }
  695.             }
  696.  
  697.         } elseif ('file' == $this->getElementType($elementName)) {
  698.             return $this->getElementValue($elementName);
  699.  
  700.         } elseif ('group' == $this->getElementType($elementName)) {
  701.             $group    =& $this->getElement($elementName);
  702.             $elements =& $group->getElements();
  703.             foreach (array_keys($elements) as $key) {
  704.                 $name = $group->getElementName($key);
  705.                 if ($name != $elementName) {
  706.                     // filter out radios
  707.                     $value[$name] = $this->getSubmitValue($name);
  708.                 }
  709.             }
  710.  
  711.         } elseif (false !== ($pos = strpos($elementName, '['))) {
  712.             $base = substr($elementName, 0, $pos);
  713.             $idx  = "['" . str_replace(array(']', '['), array('', "']['"), substr($elementName, $pos + 1, -1)) . "']";
  714.             if (isset($this->_submitValues[$base])) {
  715.                 $value = eval("return (isset(\$this->_submitValues['{$base}']{$idx})) ? \$this->_submitValues['{$base}']{$idx} : null;");
  716.             }
  717.  
  718.             if (null === $value && isset($this->_submitFiles[$base])) {
  719.                 $props = array('name', 'type', 'size', 'tmp_name', 'error');
  720.                 $code  = "if (!isset(\$this->_submitFiles['{$base}']['name']{$idx})) {\n" .
  721.                          "    return null;\n" .
  722.                          "} else {\n" .
  723.                          "    \$v = array();\n";
  724.                 foreach ($props as $prop) {
  725.                     $code .= "    \$v['{$prop}'] = \$this->_submitFiles['{$base}']['{$prop}']{$idx};\n";
  726.                 }
  727.                 $value = eval($code . "    return \$v;\n}\n");
  728.             }
  729.         }
  730.         return $value;
  731.     } // end func getSubmitValue
  732.  
  733.     // }}}
  734.     // {{{ _reindexFiles()
  735.  
  736.    /**
  737.     * A helper function to change the indexes in $_FILES array
  738.     *
  739.     * @param  mixed   Some value from the $_FILES array
  740.     * @param  string  The key from the $_FILES array that should be appended
  741.     * @return array
  742.     */
  743.     function _reindexFiles($value, $key)
  744.     {
  745.         if (!is_array($value)) {
  746.             return array($key => $value);
  747.         } else {
  748.             $ret = array();
  749.             foreach ($value as $k => $v) {
  750.                 $ret[$k] = $this->_reindexFiles($v, $key);
  751.             }
  752.             return $ret;
  753.         }
  754.     }
  755.  
  756.     // }}}
  757.     // {{{ getElementError()
  758.  
  759.     /**
  760.      * Returns error corresponding to validated element
  761.      *
  762.      * @param     string    $element        Name of form element to check
  763.      * @since     1.0
  764.      * @access    public
  765.      * @return    string    error message corresponding to checked element
  766.      */
  767.     function getElementError($element)
  768.     {
  769.         if (isset($this->_errors[$element])) {
  770.             return $this->_errors[$element];
  771.         }
  772.     } // end func getElementError
  773.     
  774.     // }}}
  775.     // {{{ setElementError()
  776.  
  777.     /**
  778.      * Set error message for a form element
  779.      *
  780.      * @param     string    $element    Name of form element to set error for
  781.      * @param     string    $message    Error message
  782.      * @since     1.0       
  783.      * @access    public
  784.      * @return    void
  785.      */
  786.     function setElementError($element,$message)
  787.     {
  788.         $this->_errors[$element] = $message;
  789.     } // end func setElementError
  790.          
  791.      // }}}
  792.      // {{{ getElementType()
  793.  
  794.      /**
  795.       * Returns the type of the given element
  796.       *
  797.       * @param      string    $element    Name of form element
  798.       * @since      1.1
  799.       * @access     public
  800.       * @return     string    Type of the element, false if the element is not found
  801.       */
  802.      function getElementType($element)
  803.      {
  804.          if (isset($this->_elementIndex[$element])) {
  805.              return $this->_elements[$this->_elementIndex[$element]]->getType();
  806.          }
  807.          return false;
  808.      } // end func getElementType
  809.  
  810.      // }}}
  811.      // {{{ updateElementAttr()
  812.  
  813.     /**
  814.      * Updates Attributes for one or more elements
  815.      *
  816.      * @param      mixed    $elements   Array of element names/objects or string of elements to be updated
  817.      * @param      mixed    $attrs      Array or sting of html attributes
  818.      * @since      2.10
  819.      * @access     public
  820.      * @return     void
  821.      */
  822.     function updateElementAttr($elements, $attrs)
  823.     {
  824.         if (is_string($elements)) {
  825.             $elements = split('[ ]?,[ ]?', $elements);
  826.         }
  827.         foreach (array_keys($elements) as $key) {
  828.             if (is_object($elements[$key]) && is_a($elements[$key], 'HTML_QuickForm_element')) {
  829.                 $elements[$key]->updateAttributes($attrs);
  830.             } elseif (isset($this->_elementIndex[$elements[$key]])) {
  831.                 $this->_elements[$this->_elementIndex[$elements[$key]]]->updateAttributes($attrs);
  832.                 if (isset($this->_duplicateIndex[$elements[$key]])) {
  833.                     foreach ($this->_duplicateIndex[$elements[$key]] as $index) {
  834.                         $this->_elements[$index]->updateAttributes($attrs);
  835.                     }
  836.                 }
  837.             }
  838.         }
  839.     } // end func updateElementAttr
  840.  
  841.     // }}}
  842.     // {{{ removeElement()
  843.  
  844.     /**
  845.      * Removes an element
  846.      *
  847.      * @param string    $elementName The element name
  848.      * @param boolean   $removeRules True if rules for this element are to be removed too                     
  849.      *
  850.      * @access public
  851.      * @since 2.0
  852.      * @return void
  853.      * @throws HTML_QuickForm_Error
  854.      */
  855.    function removeElement($elementName, $removeRules = true)
  856.     {
  857.         if (isset($this->_elementIndex[$elementName])) {
  858.             unset($this->_elements[$this->_elementIndex[$elementName]]);
  859.             unset($this->_elementIndex[$elementName]);
  860.             if ($removeRules) {
  861.                 unset($this->_rules[$elementName]);
  862.             }
  863.         } else {
  864.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$elementName' does not exist in HTML_QuickForm::removeElement()", 'HTML_QuickForm_Error', true);
  865.         }
  866.     } // end func removeElement
  867.  
  868.     // }}}
  869.     // {{{ addRule()
  870.  
  871.     /**
  872.      * Adds a validation rule for the given field
  873.      *
  874.      * If the element is in fact a group, it will be considered as a whole.
  875.      * To validate grouped elements as separated entities, 
  876.      * use addGroupRule instead of addRule.
  877.      *
  878.      * @param    string     $element       Form element name
  879.      * @param    string     $message       Message to display for invalid data
  880.      * @param    string     $type          Rule type, use getRegisteredRules() to get types
  881.      * @param    string     $format        (optional)Required for extra rule data
  882.      * @param    string     $validation    (optional)Where to perform validation: "server", "client"
  883.      * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?
  884.      * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist
  885.      * @since    1.0
  886.      * @access   public
  887.      * @throws   HTML_QuickForm_Error
  888.      */
  889.     function addRule($element, $message, $type, $format=null, $validation='server', $reset = false, $force = false)
  890.     {
  891.         if (!$force) {
  892.             if (!is_array($element) && !$this->elementExists($element)) {
  893.                 return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  894.             } elseif (is_array($element)) {
  895.                 foreach ($element as $el) {
  896.                     if (!$this->elementExists($el)) {
  897.                         return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$el' does not exist in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  898.                     }
  899.                 }
  900.             }
  901.         }
  902.         if (false === ($newName = $this->isRuleRegistered($type, true))) {
  903.             return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addRule()", 'HTML_QuickForm_Error', true);
  904.         } elseif (is_string($newName)) {
  905.             $type = $newName;
  906.         }
  907.         if (is_array($element)) {
  908.             $dependent = $element;
  909.             $element   = array_shift($dependent);
  910.         } else {
  911.             $dependent = null;
  912.         }
  913.         if ($type == 'required' || $type == 'uploadedfile') {
  914.             $this->_required[] = $element;
  915.         }
  916.         if (!isset($this->_rules[$element])) {
  917.             $this->_rules[$element] = array();
  918.         }
  919.         if ($validation == 'client') {
  920.             $this->updateAttributes(array('onsubmit'=>'return validate_'.$this->_attributes['id'] . '(this);'));
  921.         }
  922.         $this->_rules[$element][] = array(
  923.             'type'        => $type,
  924.             'format'      => $format,
  925.             'message'     => $message,
  926.             'validation'  => $validation,
  927.             'reset'       => $reset,
  928.             'dependent'   => $dependent
  929.         );
  930.     } // end func addRule
  931.  
  932.     // }}}
  933.     // {{{ addGroupRule()
  934.  
  935.     /**
  936.      * Adds a validation rule for the given group of elements
  937.      *
  938.      * Only groups with a name can be assigned a validation rule
  939.      * Use addGroupRule when you need to validate elements inside the group.
  940.      * Use addRule if you need to validate the group as a whole. In this case,
  941.      * the same rule will be applied to all elements in the group.
  942.      * Use addRule if you need to validate the group against a function.
  943.      *
  944.      * @param    string     $group         Form group name
  945.      * @param    mixed      $arg1          Array for multiple elements or error message string for one element
  946.      * @param    string     $type          (optional)Rule type use getRegisteredRules() to get types
  947.      * @param    string     $format        (optional)Required for extra rule data
  948.      * @param    int        $howmany       (optional)How many valid elements should be in the group
  949.      * @param    string     $validation    (optional)Where to perform validation: "server", "client"
  950.      * @param    bool       $reset         Client-side: whether to reset the element's value to its original state if validation failed.
  951.      * @since    2.5
  952.      * @access   public
  953.      * @throws   HTML_QuickForm_Error
  954.      */
  955.     function addGroupRule($group, $arg1, $type='', $format=null, $howmany=0, $validation = 'server', $reset = false)
  956.     {
  957.         if (!$this->elementExists($group)) {
  958.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Group '$group' does not exist in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  959.         }
  960.  
  961.         $groupObj =& $this->getElement($group);
  962.         if (is_array($arg1)) {
  963.             $required = 0;
  964.             foreach ($arg1 as $elementIndex => $rules) {
  965.                 $elementName = $groupObj->getElementName($elementIndex);
  966.                 foreach ($rules as $rule) {
  967.                     $format = (isset($rule[2])) ? $rule[2] : null;
  968.                     $validation = (isset($rule[3]) && 'client' == $rule[3])? 'client': 'server';
  969.                     $reset = isset($rule[4]) && $rule[4];
  970.                     $type = $rule[1];
  971.                     if (false === ($newName = $this->isRuleRegistered($type, true))) {
  972.                         return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  973.                     } elseif (is_string($newName)) {
  974.                         $type = $newName;
  975.                     }
  976.  
  977.                     $this->_rules[$elementName][] = array(
  978.                                                         'type'        => $type,
  979.                                                         'format'      => $format, 
  980.                                                         'message'     => $rule[0],
  981.                                                         'validation'  => $validation,
  982.                                                         'reset'       => $reset,
  983.                                                         'group'       => $group);
  984.  
  985.                     if ('required' == $type || 'uploadedfile' == $type) {
  986.                         $groupObj->_required[] = $elementName;
  987.                         $this->_required[] = $elementName;
  988.                         $required++;
  989.                     }
  990.                     if ('client' == $validation) {
  991.                         $this->updateAttributes(array('onsubmit'=>'return validate_'.$this->_attributes['id'] . '(this);'));
  992.                     }
  993.                 }
  994.             }
  995.             if ($required > 0 && count($groupObj->getElements()) == $required) {
  996.                 $this->_required[] = $group;
  997.             }
  998.         } elseif (is_string($arg1)) {
  999.             if (false === ($newName = $this->isRuleRegistered($type, true))) {
  1000.                 return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, "Rule '$type' is not registered in HTML_QuickForm::addGroupRule()", 'HTML_QuickForm_Error', true);
  1001.             } elseif (is_string($newName)) {
  1002.                 $type = $newName;
  1003.             }
  1004.  
  1005.             // Radios need to be handled differently when required
  1006.             if ($type == 'required' && $groupObj->getGroupType() == 'radio') {
  1007.                 $howmany = ($howmany == 0) ? 1 : $howmany;
  1008.             } else {
  1009.                 $howmany = ($howmany == 0) ? count($groupObj->getElements()) : $howmany;
  1010.             }
  1011.  
  1012.             $this->_rules[$group][] = array('type'       => $type,
  1013.                                             'format'     => $format, 
  1014.                                             'message'    => $arg1,
  1015.                                             'validation' => $validation,
  1016.                                             'howmany'    => $howmany,
  1017.                                             'reset'      => $reset);
  1018.             if ($type == 'required') {
  1019.                 $this->_required[] = $group;
  1020.             }
  1021.             if ($validation == 'client') {
  1022.                 $this->updateAttributes(array('onsubmit'=>'return validate_'.$this->_attributes['id'] . '(this);'));
  1023.             }
  1024.         }
  1025.     } // end func addGroupRule
  1026.  
  1027.     // }}}
  1028.     // {{{ addFormRule()
  1029.  
  1030.    /**
  1031.     * Adds a global validation rule 
  1032.     * 
  1033.     * This should be used when for a rule involving several fields or if
  1034.     * you want to use some completely custom validation for your form.
  1035.     * The rule function/method should return true in case of successful 
  1036.     * validation and array('element name' => 'error') when there were errors.
  1037.     * 
  1038.     * @access   public
  1039.     * @param    mixed   Callback, either function name or array(&$object, 'method')
  1040.     * @throws   HTML_QuickForm_Error
  1041.     */
  1042.     function addFormRule($rule)
  1043.     {
  1044.         if (!is_callable($rule)) {
  1045.             return PEAR::raiseError(null, QUICKFORM_INVALID_RULE, null, E_USER_WARNING, 'Callback function does not exist in HTML_QuickForm::addFormRule()', 'HTML_QuickForm_Error', true);
  1046.         }
  1047.         $this->_formRules[] = $rule;
  1048.     }
  1049.     
  1050.     // }}}
  1051.     // {{{ applyFilter()
  1052.  
  1053.     /**
  1054.      * Applies a data filter for the given field(s)
  1055.      *
  1056.      * @param    mixed     $element       Form element name or array of such names
  1057.      * @param    mixed     $filter        Callback, either function name or array(&$object, 'method')
  1058.      * @since    2.0
  1059.      * @access   public
  1060.      */
  1061.     function applyFilter($element, $filter)
  1062.     {
  1063.         if (!is_callable($filter)) {
  1064.             return PEAR::raiseError(null, QUICKFORM_INVALID_FILTER, null, E_USER_WARNING, "Callback function does not exist in QuickForm::applyFilter()", 'HTML_QuickForm_Error', true);
  1065.         }
  1066.         if ($element == '__ALL__') {
  1067.             $this->_submitValues = $this->_recursiveFilter($filter, $this->_submitValues);
  1068.         } else {
  1069.             if (!is_array($element)) {
  1070.                 $element = array($element);
  1071.             }
  1072.             foreach ($element as $elName) {
  1073.                 $value = $this->getSubmitValue($elName);
  1074.                 if (null !== $value) {
  1075.                     if (false === strpos($elName, '[')) {
  1076.                         $this->_submitValues[$elName] = $this->_recursiveFilter($filter, $value);
  1077.                     } else {
  1078.                         $idx  = "['" . str_replace(array(']', '['), array('', "']['"), $elName) . "']";
  1079.                         eval("\$this->_submitValues{$idx} = \$this->_recursiveFilter(\$filter, \$value);");
  1080.                     }
  1081.                 }
  1082.             }
  1083.         }
  1084.     } // end func applyFilter
  1085.  
  1086.     // }}}
  1087.     // {{{ _recursiveFilter()
  1088.  
  1089.     /**
  1090.      * Recursively apply a filter function
  1091.      *
  1092.      * @param     string   $filter    filter to apply
  1093.      * @param     mixed    $value     submitted values
  1094.      * @since     2.0
  1095.      * @access    private
  1096.      * @return    cleaned values
  1097.      */
  1098.     function _recursiveFilter($filter, $value)
  1099.     {
  1100.         if (is_array($value)) {
  1101.             $cleanValues = array();
  1102.             foreach ($value as $k => $v) {
  1103.                 $cleanValues[$k] = $this->_recursiveFilter($filter, $value[$k]);
  1104.             }
  1105.             return $cleanValues;
  1106.         } else {
  1107.             return call_user_func($filter, $value);
  1108.         }
  1109.     } // end func _recursiveFilter
  1110.  
  1111.     // }}}
  1112.     // {{{ arrayMerge()
  1113.  
  1114.    /**
  1115.     * Merges two arrays
  1116.     *
  1117.     * Merges two array like the PHP function array_merge but recursively.
  1118.     * The main difference is that existing keys will not be renumbered
  1119.     * if they are integers.
  1120.     *
  1121.     * @access   puplic
  1122.     * @param    array   $a  original array
  1123.     * @param    array   $b  array which will be merged into first one
  1124.     * @return   array   merged array
  1125.     */
  1126.     function arrayMerge($a, $b)
  1127.     {
  1128.         foreach ($b as $k => $v) {
  1129.             if (is_array($v)) {
  1130.                 if (isset($a[$k]) && !is_array($a[$k])) {
  1131.                     $a[$k] = $v;
  1132.                 } else {
  1133.                     if (!isset($a[$k])) {
  1134.                         $a[$k] = array();
  1135.                     }
  1136.                     $a[$k] = HTML_QuickForm::arrayMerge($a[$k], $v);
  1137.                 }
  1138.             } else {
  1139.                 $a[$k] = $v;
  1140.             }
  1141.         }
  1142.         return $a;
  1143.     } // end func arrayMerge
  1144.  
  1145.     // }}}
  1146.     // {{{ isTypeRegistered()
  1147.  
  1148.     /**
  1149.      * Returns whether or not the form element type is supported
  1150.      *
  1151.      * @param     string   $type     Form element type
  1152.      * @since     1.0
  1153.      * @access    public
  1154.      * @return    boolean
  1155.      */
  1156.     function isTypeRegistered($type)
  1157.     {
  1158.         return isset($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES'][$type]);
  1159.     } // end func isTypeRegistered
  1160.  
  1161.     // }}}
  1162.     // {{{ getRegisteredTypes()
  1163.  
  1164.     /**
  1165.      * Returns an array of registered element types
  1166.      *
  1167.      * @since     1.0
  1168.      * @access    public
  1169.      * @return    array
  1170.      */
  1171.     function getRegisteredTypes()
  1172.     {
  1173.         return array_keys($GLOBALS['HTML_QUICKFORM_ELEMENT_TYPES']);
  1174.     } // end func getRegisteredTypes
  1175.  
  1176.     // }}}
  1177.     // {{{ isRuleRegistered()
  1178.  
  1179.     /**
  1180.      * Returns whether or not the given rule is supported
  1181.      *
  1182.      * @param     string   $name    Validation rule name
  1183.      * @param     bool     Whether to automatically register subclasses of HTML_QuickForm_Rule
  1184.      * @since     1.0
  1185.      * @access    public
  1186.      * @return    mixed    true if previously registered, false if not, new rule name if auto-registering worked
  1187.      */
  1188.     function isRuleRegistered($name, $autoRegister = false)
  1189.     {
  1190.         if (is_scalar($name) && isset($GLOBALS['_HTML_QuickForm_registered_rules'][$name])) {
  1191.             return true;
  1192.         } elseif (!$autoRegister) {
  1193.             return false;
  1194.         }
  1195.         // automatically register the rule if requested
  1196.         include_once 'HTML/QuickForm/RuleRegistry.php';
  1197.         $ruleName = false;
  1198.         if (is_object($name) && is_a($name, 'html_quickform_rule')) {
  1199.             $ruleName = !empty($name->name)? $name->name: strtolower(get_class($name));
  1200.         } elseif (is_string($name) && class_exists($name)) {
  1201.             $parent = strtolower($name);
  1202.             do {
  1203.                 if ('html_quickform_rule' == strtolower($parent)) {
  1204.                     $ruleName = strtolower($name);
  1205.                     break;
  1206.                 }
  1207.             } while ($parent = get_parent_class($parent));
  1208.         }
  1209.         if ($ruleName) {
  1210.             $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1211.             $registry->registerRule($ruleName, null, $name);
  1212.         }
  1213.         return $ruleName;
  1214.     } // end func isRuleRegistered
  1215.  
  1216.     // }}}
  1217.     // {{{ getRegisteredRules()
  1218.  
  1219.     /**
  1220.      * Returns an array of registered validation rules
  1221.      *
  1222.      * @since     1.0
  1223.      * @access    public
  1224.      * @return    array
  1225.      */
  1226.     function getRegisteredRules()
  1227.     {
  1228.         return array_keys($GLOBALS['_HTML_QuickForm_registered_rules']);
  1229.     } // end func getRegisteredRules
  1230.  
  1231.     // }}}
  1232.     // {{{ isElementRequired()
  1233.  
  1234.     /**
  1235.      * Returns whether or not the form element is required
  1236.      *
  1237.      * @param     string   $element     Form element name
  1238.      * @since     1.0
  1239.      * @access    public
  1240.      * @return    boolean
  1241.      */
  1242.     function isElementRequired($element)
  1243.     {
  1244.         return in_array($element, $this->_required, true);
  1245.     } // end func isElementRequired
  1246.  
  1247.     // }}}
  1248.     // {{{ isElementFrozen()
  1249.  
  1250.     /**
  1251.      * Returns whether or not the form element is frozen
  1252.      *
  1253.      * @param     string   $element     Form element name
  1254.      * @since     1.0
  1255.      * @access    public
  1256.      * @return    boolean
  1257.      */
  1258.     function isElementFrozen($element)
  1259.     {
  1260.          if (isset($this->_elementIndex[$element])) {
  1261.              return $this->_elements[$this->_elementIndex[$element]]->isFrozen();
  1262.          }
  1263.          return false;
  1264.     } // end func isElementFrozen
  1265.  
  1266.     // }}}
  1267.     // {{{ setJsWarnings()
  1268.  
  1269.     /**
  1270.      * Sets JavaScript warning messages
  1271.      *
  1272.      * @param     string   $pref        Prefix warning
  1273.      * @param     string   $post        Postfix warning
  1274.      * @since     1.1
  1275.      * @access    public
  1276.      * @return    void
  1277.      */
  1278.     function setJsWarnings($pref, $post)
  1279.     {
  1280.         $this->_jsPrefix = $pref;
  1281.         $this->_jsPostfix = $post;
  1282.     } // end func setJsWarnings
  1283.     
  1284.     // }}}
  1285.     // {{{ setRequiredNote()
  1286.  
  1287.     /**
  1288.      * Sets required-note
  1289.      *
  1290.      * @param     string   $note        Message indicating some elements are required
  1291.      * @since     1.1
  1292.      * @access    public
  1293.      * @return    void
  1294.      */
  1295.     function setRequiredNote($note)
  1296.     {
  1297.         $this->_requiredNote = $note;
  1298.     } // end func setRequiredNote
  1299.  
  1300.     // }}}
  1301.     // {{{ getRequiredNote()
  1302.  
  1303.     /**
  1304.      * Returns the required note
  1305.      *
  1306.      * @since     2.0
  1307.      * @access    public
  1308.      * @return    string
  1309.      */
  1310.     function getRequiredNote()
  1311.     {
  1312.         return $this->_requiredNote;
  1313.     } // end func getRequiredNote
  1314.  
  1315.     // }}}
  1316.     // {{{ validate()
  1317.  
  1318.     /**
  1319.      * Performs the server side validation
  1320.      * @access    public
  1321.      * @since     1.0
  1322.      * @return    boolean   true if no error found
  1323.      */
  1324.     function validate()
  1325.     {
  1326.         if (count($this->_rules) == 0 && count($this->_formRules) == 0 && 
  1327.             (count($this->_submitValues) > 0 || count($this->_submitFiles) > 0)) {
  1328.             return true;
  1329.         } elseif (count($this->_submitValues) == 0 && count($this->_submitFiles) == 0) {
  1330.             return false;
  1331.         }
  1332.  
  1333.         include_once('HTML/QuickForm/RuleRegistry.php');
  1334.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1335.  
  1336.         foreach ($this->_rules as $target => $rules) {
  1337.             $submitValue = $this->getSubmitValue($target);
  1338.  
  1339.             foreach ($rules as $elementName => $rule) {
  1340.                 if ((isset($rule['group']) && isset($this->_errors[$rule['group']])) ||
  1341.                      isset($this->_errors[$target])) {
  1342.                     continue 2;
  1343.                 }
  1344.                 if ((!isset($submitValue) || $submitValue == '') && 
  1345.                      !$this->isElementRequired($target)) {
  1346.                     // Element is not required
  1347.                     continue 2;
  1348.                 }
  1349.                 if (isset($rule['dependent']) && is_array($rule['dependent'])) {
  1350.                     $values = array($submitValue);
  1351.                     foreach ($rule['dependent'] as $elName) {
  1352.                         $values[] = $this->getSubmitValue($elName);
  1353.                     }
  1354.                     $result = $registry->validate($rule['type'], $values, $rule['format'], true);
  1355.                 } elseif (is_array($submitValue) && !isset($rule['howmany'])) {
  1356.                     $result = $registry->validate($rule['type'], $submitValue, $rule['format'], true);
  1357.                 } else {
  1358.                     $result = $registry->validate($rule['type'], $submitValue, $rule['format'], false);
  1359.                 }
  1360.  
  1361.                 if (!$result || (!empty($rule['howmany']) && $rule['howmany'] > (int)$result)) {
  1362.                     if (isset($rule['group'])) {
  1363.                         $this->_errors[$rule['group']] = $rule['message'];
  1364.                     } else {
  1365.                         $this->_errors[$target] = $rule['message'];
  1366.                     }
  1367.                 }
  1368.             }
  1369.         }
  1370.  
  1371.         // process the global rules now
  1372.         foreach ($this->_formRules as $rule) {
  1373.             if (true !== ($res = call_user_func($rule, $this->_submitValues, $this->_submitFiles))) {
  1374.                 if (is_array($res)) {
  1375.                     $this->_errors += $res;
  1376.                 } else {
  1377.                     return PEAR::raiseError(null, QUICKFORM_ERROR, null, E_USER_WARNING, 'Form rule callback returned invalid value in HTML_QuickForm::validate()', 'HTML_QuickForm_Error', true);
  1378.                 }
  1379.             }
  1380.         }
  1381.  
  1382.         return (0 == count($this->_errors));
  1383.     } // end func validate
  1384.  
  1385.     // }}}
  1386.     // {{{ freeze()
  1387.  
  1388.     /**
  1389.      * Displays elements without HTML input tags
  1390.      *
  1391.      * @param    mixed   $elementList       array or string of element(s) to be frozen
  1392.      * @since     1.0
  1393.      * @access   public
  1394.      * @throws   HTML_QuickForm_Error
  1395.      */
  1396.     function freeze($elementList=null)
  1397.     {
  1398.         $elementFlag = false;
  1399.         if (isset($elementList) && !is_array($elementList)) {
  1400.             $elementList = split('[ ]*,[ ]*', $elementList);
  1401.         } elseif (!isset($elementList)) {
  1402.             $this->_freezeAll = true;
  1403.         }
  1404.  
  1405.         foreach ($this->_elements as $key => $val) {
  1406.             // need to get the element by reference
  1407.             $element = &$this->_elements[$key];
  1408.             if (is_object($element)) {
  1409.                 $name = $element->getName();
  1410.                 if ($this->_freezeAll || in_array($name, $elementList)) {
  1411.                     $elementFlag = true;
  1412.                     $element->freeze();
  1413.                 }
  1414.             }
  1415.         }
  1416.  
  1417.         if (!$elementFlag) {
  1418.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::freeze()", 'HTML_QuickForm_Error', true);
  1419.         }
  1420.         return true;
  1421.     } // end func freeze
  1422.         
  1423.     // }}}
  1424.     // {{{ isFrozen()
  1425.  
  1426.     /**
  1427.      * Returns whether or not the whole form is frozen
  1428.      *
  1429.      * @since     3.0
  1430.      * @access    public
  1431.      * @return    boolean
  1432.      */
  1433.     function isFrozen()
  1434.     {
  1435.          return $this->_freezeAll;
  1436.     } // end func isFrozen
  1437.  
  1438.     // }}}
  1439.     // {{{ process()
  1440.  
  1441.     /**
  1442.      * Performs the form data processing
  1443.      *
  1444.      * @param    mixed     $callback        Callback, either function name or array(&$object, 'method')
  1445.      * @param    bool      $mergeFiles      Whether uploaded files should be processed too
  1446.      * @since    1.0
  1447.      * @access   public
  1448.      * @throws   HTML_QuickForm_Error
  1449.      */
  1450.     function process($callback, $mergeFiles = true)
  1451.     {
  1452.         if (!is_callable($callback)) {
  1453.             return PEAR::raiseError(null, QUICKFORM_INVALID_PROCESS, null, E_USER_WARNING, "Callback function does not exist in QuickForm::process()", 'HTML_QuickForm_Error', true);
  1454.         }
  1455.         $values = ($mergeFiles === true) ? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles) : $this->_submitValues;
  1456.         return call_user_func($callback, $values);
  1457.     } // end func process
  1458.  
  1459.     // }}}
  1460.     // {{{ accept()
  1461.  
  1462.    /**
  1463.     * Accepts a renderer
  1464.     *
  1465.     * @param object     An HTML_QuickForm_Renderer object
  1466.     * @since 3.0
  1467.     * @access public
  1468.     * @return void
  1469.     */
  1470.     function accept(&$renderer)
  1471.     {
  1472.         $renderer->startForm($this);
  1473.         foreach (array_keys($this->_elements) as $key) {
  1474.             $element =& $this->_elements[$key];
  1475.             if ($this->_freezeAll) {
  1476.                 $element->freeze();
  1477.             }
  1478.             $elementName = $element->getName();
  1479.             $required    = ($this->isElementRequired($elementName) && $this->_freezeAll == false);
  1480.             $error       = $this->getElementError($elementName);
  1481.             $element->accept($renderer, $required, $error);
  1482.         }
  1483.         $renderer->finishForm($this);
  1484.     } // end func accept
  1485.  
  1486.     // }}}
  1487.     // {{{ defaultRenderer()
  1488.  
  1489.    /**
  1490.     * Returns a reference to default renderer object
  1491.     *
  1492.     * @access public
  1493.     * @since 3.0
  1494.     * @return object a default renderer object
  1495.     */
  1496.     function &defaultRenderer()
  1497.     {
  1498.         if (!isset($GLOBALS['_HTML_QuickForm_default_renderer'])) {
  1499.             include_once('HTML/QuickForm/Renderer/Default.php');
  1500.             $GLOBALS['_HTML_QuickForm_default_renderer'] =& new HTML_QuickForm_Renderer_Default();
  1501.         }
  1502.         return $GLOBALS['_HTML_QuickForm_default_renderer'];
  1503.     } // end func defaultRenderer
  1504.  
  1505.     // }}}
  1506.     // {{{ toHtml ()
  1507.  
  1508.     /**
  1509.      * Returns an HTML version of the form
  1510.      *
  1511.      * @param string $in_data (optional) Any extra data to insert right
  1512.      *               before form is rendered.  Useful when using templates.
  1513.      *
  1514.      * @return   string     Html version of the form
  1515.      * @since     1.0
  1516.      * @access   public
  1517.      */
  1518.     function toHtml ($in_data = null)
  1519.     {
  1520.         if (!is_null($in_data)) {
  1521.             $this->addElement('html', $in_data);
  1522.         }
  1523.         $renderer =& $this->defaultRenderer();
  1524.         $this->accept($renderer);
  1525.         return $renderer->toHtml();
  1526.     } // end func toHtml
  1527.  
  1528.     // }}}
  1529.     // {{{ getValidationScript()
  1530.  
  1531.     /**
  1532.      * Returns the client side validation script
  1533.      *
  1534.      * @since     2.0
  1535.      * @access    public
  1536.      * @return    string    Javascript to perform validation, empty string if no 'client' rules were added
  1537.      */
  1538.     function getValidationScript()
  1539.     {
  1540.         if (empty($this->_rules) || $this->_freezeAll || empty($this->_attributes['onsubmit'])) {
  1541.             return '';
  1542.         }
  1543.  
  1544.         include_once('HTML/QuickForm/RuleRegistry.php');
  1545.         $registry =& HTML_QuickForm_RuleRegistry::singleton();
  1546.         $test = array();
  1547.         $js_escape = array(
  1548.             "\r"    => '\r',
  1549.             "\n"    => '\n',
  1550.             "\t"    => '\t',
  1551.             "'"     => "\\'",
  1552.             '"'     => '\"',
  1553.             '\\'    => '\\\\'
  1554.         );
  1555.  
  1556.         foreach ($this->_rules as $elementName => $rules) {
  1557.             foreach ($rules as $rule) {
  1558.                 if ('client' == $rule['validation']) {
  1559.                     $dependent  = isset($rule['dependent']) && is_array($rule['dependent']);
  1560.                     $rule['message'] = strtr($rule['message'], $js_escape);
  1561.  
  1562.                     if (isset($rule['group'])) {
  1563.                         $group    =& $this->getElement($rule['group']);
  1564.                         // No JavaScript validation for frozen elements
  1565.                         if ($group->isFrozen()) {
  1566.                             continue 2;
  1567.                         }
  1568.                         $elements =& $group->getElements();
  1569.                         foreach (array_keys($elements) as $key) {
  1570.                             if ($elementName == $group->getElementName($key)) {
  1571.                                 $element =& $elements[$key];
  1572.                                 break;
  1573.                             }
  1574.                         }
  1575.                     } elseif ($dependent) {
  1576.                         $element   =  array();
  1577.                         $element[] =& $this->getElement($elementName);
  1578.                         foreach ($rule['dependent'] as $idx => $elName) {
  1579.                             $element[] =& $this->getElement($elName);
  1580.                         }
  1581.                     } else {
  1582.                         $element =& $this->getElement($elementName);
  1583.                     }
  1584.                     // No JavaScript validation for frozen elements
  1585.                     if (is_object($element) && $element->isFrozen()) {
  1586.                         continue 2;
  1587.                     } elseif (is_array($element)) {
  1588.                         foreach (array_keys($element) as $key) {
  1589.                             if ($element[$key]->isFrozen()) {
  1590.                                 continue 3;
  1591.                             }
  1592.                         }
  1593.                     }
  1594.  
  1595.                     $test[] = $registry->getValidationScript($element, $elementName, $rule);
  1596.                     unset($element);
  1597.                 }
  1598.             }
  1599.         }
  1600.         if (count($test) > 0) {
  1601.             return
  1602.                 "\n<script type=\"text/javascript\">\n" .
  1603.                 "//<![CDATA[\n" . 
  1604.                 "function validate_" . $this->_attributes['id'] . "(frm) {\n" .
  1605.                 "  var value = '';\n" .
  1606.                 "  var errFlag = new Array();\n" .
  1607.                 "  _qfMsg = '';\n\n" .
  1608.                 join("\n", $test) .
  1609.                 "\n  if (_qfMsg != '') {\n" .
  1610.                 "    _qfMsg = '" . strtr($this->_jsPrefix, $js_escape) . "' + _qfMsg;\n" .
  1611.                 "    _qfMsg = _qfMsg + '\\n" . strtr($this->_jsPostfix, $js_escape) . "';\n" .
  1612.                 "    alert(_qfMsg);\n" .
  1613.                 "    return false;\n" .
  1614.                 "  }\n" .
  1615.                 "  return true;\n" .
  1616.                 "}\n" .
  1617.                 "//]]>\n" .
  1618.                 "</script>";
  1619.         }
  1620.         return '';
  1621.     } // end func getValidationScript
  1622.  
  1623.     // }}}
  1624.     // {{{ getSubmitValues()
  1625.  
  1626.     /**
  1627.      * Returns the values submitted by the form
  1628.      *
  1629.      * @since     2.0
  1630.      * @access    public
  1631.      * @param     bool      Whether uploaded files should be returned too
  1632.      * @return    array
  1633.      */
  1634.     function getSubmitValues($mergeFiles = false)
  1635.     {
  1636.         return $mergeFiles? HTML_QuickForm::arrayMerge($this->_submitValues, $this->_submitFiles): $this->_submitValues;
  1637.     } // end func getSubmitValues
  1638.  
  1639.     // }}}
  1640.     // {{{ toArray()
  1641.  
  1642.     /**
  1643.      * Returns the form's contents in an array.
  1644.      *
  1645.      * The description of the array structure is in HTML_QuickForm_Renderer_Array docs
  1646.      * 
  1647.      * @since     2.0
  1648.      * @access    public
  1649.      * @param     bool      Whether to collect hidden elements (passed to the Renderer's constructor)
  1650.      * @return    array of form contents
  1651.      */
  1652.     function toArray($collectHidden = false)
  1653.     {
  1654.         include_once 'HTML/QuickForm/Renderer/Array.php';
  1655.         $renderer =& new HTML_QuickForm_Renderer_Array($collectHidden);
  1656.         $this->accept($renderer);
  1657.         return $renderer->toArray();
  1658.      } // end func toArray
  1659.  
  1660.     // }}}
  1661.     // {{{ exportValue()
  1662.  
  1663.     /**
  1664.      * Returns a 'safe' element's value
  1665.      * 
  1666.      * This method first tries to find a cleaned-up submitted value,
  1667.      * it will return a value set by setValue()/setDefaults()/setConstants()
  1668.      * if submitted value does not exist for the given element.
  1669.      *
  1670.      * @param  string   Name of an element
  1671.      * @access public
  1672.      * @return mixed
  1673.      */
  1674.     function exportValue($element)
  1675.     {
  1676.         if (!isset($this->_elementIndex[$element])) {
  1677.             return PEAR::raiseError(null, QUICKFORM_NONEXIST_ELEMENT, null, E_USER_WARNING, "Element '$element' does not exist in HTML_QuickForm::getElementValue()", 'HTML_QuickForm_Error', true);
  1678.         }
  1679.         $value = $this->_elements[$this->_elementIndex[$element]]->exportValue($this->_submitValues, false);
  1680.         if (isset($this->_duplicateIndex[$element])) {
  1681.             foreach ($this->_duplicateIndex[$element] as $index) {
  1682.                 if (null !== ($v = $this->_elements[$index]->exportValue($this->_submitValues, false))) {
  1683.                     if (is_array($value)) {
  1684.                         $value[] = $v;
  1685.                     } else {
  1686.                         $value = (null === $value)? $v: array($value, $v);
  1687.                     }
  1688.                 }
  1689.             }
  1690.         }
  1691.         return $value;
  1692.     }
  1693.  
  1694.     // }}}
  1695.     // {{{ exportValues()
  1696.  
  1697.     /**
  1698.      * Returns 'safe' elements' values
  1699.      *
  1700.      * Unlike getSubmitValues(), this will return only the values 
  1701.      * corresponding to the elements present in the form.
  1702.      * 
  1703.      * @param   mixed   Array/string of element names, whose values we want. If not set then return all elements.
  1704.      * @access  public
  1705.      * @return  array   An assoc array of elements' values
  1706.      * @throws  HTML_QuickForm_Error
  1707.      */
  1708.     function exportValues($elementList = null)
  1709.     {
  1710.         $values = array();
  1711.         if (null === $elementList) {
  1712.             // iterate over all elements, calling their exportValue() methods
  1713.             foreach (array_keys($this->_elements) as $key) {
  1714.                 $value = $this->_elements[$key]->exportValue($this->_submitValues, true);
  1715.                 if (is_array($value)) {
  1716.                     // This shit throws a bogus warning in PHP 4.3.x
  1717.                     $values = HTML_QuickForm::arrayMerge($values, $value);
  1718.                 }
  1719.             }
  1720.         } else {
  1721.             if (!is_array($elementList)) {
  1722.                 $elementList = array_map('trim', explode(',', $elementList));
  1723.             }
  1724.             foreach ($elementList as $elementName) {
  1725.                 $value = $this->exportValue($elementName);
  1726.                 if (PEAR::isError($value)) {
  1727.                     return $value;
  1728.                 }
  1729.                 $values[$elementName] = $value;
  1730.             }
  1731.         }
  1732.         return $values;
  1733.     }
  1734.  
  1735.     // }}}
  1736.     // {{{ isError()
  1737.  
  1738.     /**
  1739.      * Tell whether a result from a QuickForm method is an error (an instance of HTML_QuickForm_Error)
  1740.      *
  1741.      * @access public
  1742.      * @param mixed     result code
  1743.      * @return bool     whether $value is an error
  1744.      */
  1745.     function isError($value)
  1746.     {
  1747.         return (is_object($value) && is_a($value, 'html_quickform_error'));
  1748.     } // end func isError
  1749.  
  1750.     // }}}
  1751.     // {{{ errorMessage()
  1752.  
  1753.     /**
  1754.      * Return a textual error message for an QuickForm error code
  1755.      *
  1756.      * @access  public
  1757.      * @param   int     error code
  1758.      * @return  string  error message
  1759.      */
  1760.     function errorMessage($value)
  1761.     {
  1762.         // make the variable static so that it only has to do the defining on the first call
  1763.         static $errorMessages;
  1764.  
  1765.         // define the varies error messages
  1766.         if (!isset($errorMessages)) {
  1767.             $errorMessages = array(
  1768.                 QUICKFORM_OK                    => 'no error',
  1769.                 QUICKFORM_ERROR                 => 'unknown error',
  1770.                 QUICKFORM_INVALID_RULE          => 'the rule does not exist as a registered rule',
  1771.                 QUICKFORM_NONEXIST_ELEMENT      => 'nonexistent html element',
  1772.                 QUICKFORM_INVALID_FILTER        => 'invalid filter',
  1773.                 QUICKFORM_UNREGISTERED_ELEMENT  => 'unregistered element',
  1774.                 QUICKFORM_INVALID_ELEMENT_NAME  => 'element already exists',
  1775.                 QUICKFORM_INVALID_PROCESS       => 'process callback does not exist',
  1776.                 QUICKFORM_DEPRECATED            => 'method is deprecated',
  1777.                 QUICKFORM_INVALID_DATASOURCE    => 'datasource is not an object'
  1778.             );
  1779.         }
  1780.  
  1781.         // If this is an error object, then grab the corresponding error code
  1782.         if (HTML_QuickForm::isError($value)) {
  1783.             $value = $value->getCode();
  1784.         }
  1785.  
  1786.         // return the textual error message corresponding to the code
  1787.         return isset($errorMessages[$value]) ? $errorMessages[$value] : $errorMessages[QUICKFORM_ERROR];
  1788.     } // end func errorMessage
  1789.  
  1790.     // }}}
  1791. } // end class HTML_QuickForm
  1792.  
  1793. class HTML_QuickForm_Error extends PEAR_Error {
  1794.  
  1795.     // {{{ properties
  1796.  
  1797.     /**
  1798.     * Prefix for all error messages
  1799.     * @var string
  1800.     */
  1801.     var $error_message_prefix = 'QuickForm Error: ';
  1802.  
  1803.     // }}}
  1804.     // {{{ constructor
  1805.  
  1806.     /**
  1807.     * Creates a quickform error object, extending the PEAR_Error class
  1808.     *
  1809.     * @param int   $code the error code
  1810.     * @param int   $mode the reaction to the error, either return, die or trigger/callback
  1811.     * @param int   $level intensity of the error (PHP error code)
  1812.     * @param mixed $debuginfo any information that can inform user as to nature of the error
  1813.     */
  1814.     function HTML_QuickForm_Error($code = QUICKFORM_ERROR, $mode = PEAR_ERROR_RETURN,
  1815.                          $level = E_USER_NOTICE, $debuginfo = null)
  1816.     {
  1817.         if (is_int($code)) {
  1818.             $this->PEAR_Error(HTML_QuickForm::errorMessage($code), $code, $mode, $level, $debuginfo);
  1819.         } else {
  1820.             $this->PEAR_Error("Invalid error code: $code", QUICKFORM_ERROR, $mode, $level, $debuginfo);
  1821.         }
  1822.     }
  1823.  
  1824.     // }}}
  1825. } // end class HTML_QuickForm_Error
  1826. ?>